/*
 * Copyright© 2013-2018 YZTC 
 * Author zhenghl 
 * 本公司保留所有下述内容的权利; 
 * 本内容为保密信息，仅限本公司内部使用; 
 * 非经本公司书面许可，任何人不得外泄或用于其他目的; 
*/
package com.wxmp.wxapi.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;
import com.wxmp.core.exception.WxErrorException;
import com.wxmp.wxcms.domain.*;
import com.wxmp.wxcms.mapper.*;
import com.wxmp.wxcms.service.MsgNewsService;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wxmp.core.util.AjaxResult;
import com.wxmp.core.util.HttpClientUtils;
import com.wxmp.core.util.StringUtil;
import com.wxmp.core.util.wx.WxUtil;
import com.wxmp.wxapi.process.HttpMethod;
import com.wxmp.wxapi.process.MpAccount;
import com.wxmp.wxapi.process.MsgType;
import com.wxmp.wxapi.process.MsgXmlUtil;
import com.wxmp.wxapi.process.WxApi;
import com.wxmp.wxapi.process.WxApiClient;
import com.wxmp.wxapi.process.WxMemoryCacheClient;
import com.wxmp.wxapi.process.WxMessageBuilder;
import com.wxmp.wxapi.service.MyService;
import com.wxmp.wxapi.vo.Matchrule;
import com.wxmp.wxapi.vo.MsgRequest;
/**
 * 业务消息处理
 * 开发者根据自己的业务自行处理消息的接收与回复；
 */
@Service
public class MyServiceImpl implements MyService {
    @Resource
    private MsgBaseDao msgBaseDao;
    @Resource
    private MsgNewsDao msgNewsDao;
    @Resource
    private AccountMenuDao menuDao;
    @Resource
    private AccountMenuGroupDao menuGroupDao;
    @Resource
    private AccountFansDao fansDao;
    @Resource
    private UserTagDao userTagDao;
    @Resource
    private WxQrcodeDao wxQrcodeDao;
    @Resource
    private MsgNewsService msgNewsService;
    private Logger logger = Logger.getLogger(MyServiceImpl.class);
    /**
     * 处理消息
     * 开发者可以根据用户发送的消息和自己的业务，自行返回合适的消息；
     * @param msgRequest : 接收到的消息
     * @param mpAccount ： appId
     */
    public String processMsg(MsgRequest msgRequest, MpAccount mpAccount)  throws WxErrorException {
        String msgtype = msgRequest.getMsgType();// 接收到的消息类型
        String respXml = null;// 返回的内容；
        if (msgtype.equalsIgnoreCase(MsgType.Text.toString())) {
            /**
             * 文本消息，一般公众号接收到的都是此类型消息
             */
            respXml = this.processTextMsg(msgRequest, mpAccount);
        } else if (msgtype.equalsIgnoreCase(MsgType.Event.toString())) {// 事件消息
            /**
             * 用户订阅公众账号、点击菜单按钮的时候，会触发事件消息
             */
            respXml = this.processEventMsg(msgRequest, mpAccount);
        } else if (msgtype.equalsIgnoreCase(MsgType.SCAN.toString())) {//扫码消息
           this.processScanMsg(msgRequest, mpAccount);
        } else if (msgtype.equalsIgnoreCase(MsgType.Image.toString())) {// 图片消息
        } else if (msgtype.equalsIgnoreCase(MsgType.Location.toString())) {// 地理位置消息
        }
        if (StringUtils.isEmpty(respXml)) {
            MsgText text = msgBaseDao.getMsgTextByInputCode(MsgType.SUBSCRIBE.toString());
            if (text != null) {
                respXml = MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
            }
        }
        return respXml;
    }
    private String processTextMsg(MsgRequest msgRequest, MpAccount mpAccount) {
        String content = msgRequest.getContent();
        if (!StringUtils.isEmpty(content)) {// 文本消息
            if("海报".equals(content) ||"qrcode".equals(content)) {
                this.sendQrcodeRequest(msgRequest.getToUserName(), msgRequest.getFromUserName());
            }else {
                String tmpContent = content.trim();
                List<MsgNews> msgNews = msgNewsDao.getRandomMsgByContent(tmpContent, mpAccount.getMsgcount());
                if (!CollectionUtils.isEmpty(msgNews)) {
                    return MsgXmlUtil.newsToXml(WxMessageBuilder.getMsgResponseNews(msgRequest, msgNews));
                }
            }
        }
        return null;
    }
    private void sendSubscribMessage(String openId,String newsId,String account) throws WxErrorException {
        MsgNews msgNews  = this.msgNewsService.getById(newsId);
        if(msgNews!=null) {
            MpAccount mpAccount = WxMemoryCacheClient.getMpAccount(account);//获取缓存中的唯一账号
            JSONObject result = WxApiClient.sendCustomNews(openId, msgNews, mpAccount);
            logger.info(" 客服接口-发送图文消息：" + result.toString());
        }
    }
    private void processScanMsg(MsgRequest msgRequest, MpAccount mpAccount) throws WxErrorException {
        String key = msgRequest.getEventKey();
        logger.info("******************处理扫描事件******************");
        if(StringUtil.isNotEmpty(key)) {
            WxQrcode bean = new WxQrcode();
            bean.setId(Long.parseLong(key.replace("qrscene_", "")));
            wxQrcodeDao.addScanCount(bean);
        }
        logger.info("******************完成处理扫描事件******************");
    }
    private void sendQrcodeRequest(String toUserId,String fromUserId) {
        String httpUrl="https://saas.xqqcloud.com/console/api/wechat/qrcode/verify/send?refresh=false&originalId="+toUserId+"&openId="+fromUserId;
        String rps = HttpClientUtils.sendHttpGet(httpUrl);
        logger.info("******************发起二维码请求返回******************"+rps);
    }
    private String processEventMsg(MsgRequest msgRequest, MpAccount mpAccount) throws WxErrorException {
        String key = msgRequest.getEventKey();
        logger.info("******************处理关注或点击事件******************"+key);
        if (MsgType.SUBSCRIBE.toString().equals(msgRequest.getEvent())) {// 订阅消息
            logger.info("关注者openId----------来源["+key+"]：" + msgRequest.getFromUserName());
            String openId = msgRequest.getFromUserName();
            AccountFans fans = WxApiClient.syncAccountFans(openId, mpAccount);
            if (null != fans) {
                AccountFans tmpFans = fansDao.getByOpenId(openId);
                if (tmpFans == null) {
                    fans.setScene(key.replace("qrscene_", ""));
                    fans.setAccount(mpAccount.getAccount());
                    fansDao.add(fans);
                } else {
                    fans.setId(tmpFans.getId());
                    fansDao.update(fans);
                }
            }
            
            sendSubscribMessage(openId,"1",msgRequest.getToUserName());
            
            MsgText text = msgBaseDao.getMsgTextBySubscribe();
            if (text != null) {
                return MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
            }
        } else if (MsgType.UNSUBSCRIBE.toString().equals(msgRequest.getEvent())) {// 取消订阅消息
            MsgText text = msgBaseDao.getMsgTextByInputCode(MsgType.UNSUBSCRIBE.toString());
            if (text != null) {
                return MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
            }
        } else {// 点击事件消息
            if("qrcode".equals(key) || "1021".equals(key)) {
                this.sendQrcodeRequest(msgRequest.getToUserName(), msgRequest.getFromUserName()); 
            }
            if (!StringUtils.isEmpty(key)) {
                /**
                 * 固定消息
                 * _fix_ ：在我们创建菜单的时候，做了限制，对应的event_key 加了 _fix_
                 * 
                 * 当然开发者也可以进行修改
                 */
                if (key.startsWith("_fix_")) {
                    String baseIds = key.substring("_fix_".length());
                    if (!StringUtils.isEmpty(baseIds)) {
                        String[] idArr = baseIds.split(",");
                        if (idArr.length > 1) {// 多条图文消息
                            List<MsgNews> msgNews = msgBaseDao.listMsgNewsByBaseId(idArr);
                            if (msgNews != null && msgNews.size() > 0) {
                                return MsgXmlUtil.newsToXml(WxMessageBuilder.getMsgResponseNews(msgRequest, msgNews));
                            }
                        } else {// 图文消息，或者文本消息
                            MsgBase msg = msgBaseDao.getById(baseIds);
                            if (msg.getMsgtype().equals(MsgType.Text.toString())) {
                                MsgText text = msgBaseDao.getMsgTextByBaseId(baseIds);
                                if (text != null) {
                                    return MsgXmlUtil.textToXml(WxMessageBuilder.getMsgResponseText(msgRequest, text));
                                }
                            } else {
                                List<MsgNews> msgNews = msgBaseDao.listMsgNewsByBaseId(idArr);
                                if (msgNews != null && msgNews.size() > 0) {
                                    return MsgXmlUtil
                                            .newsToXml(WxMessageBuilder.getMsgResponseNews(msgRequest, msgNews));
                                }
                            }
                        }
                    }
                }
            }
        }
        logger.info("******************完成关注或点击事件******************"+key);
        return null;
    }
    public JSONObject publishMenu(MpAccount mpAccount) throws WxErrorException {
        List<AccountMenu> menus = menuDao.listWxMenus(new AccountMenu());
        Matchrule matchrule = new Matchrule();
        String menuJson = JSONObject.toJSONString(WxUtil.prepareMenus(menus, matchrule));
        logger.info("创建菜单传参如下:" + menuJson);
        JSONObject rstObj = WxApiClient.publishMenus(menuJson, mpAccount);// 创建普通菜单
        logger.info("创建菜单返回消息如下:" + rstObj.toString());
        return rstObj;
    }
    public JSONObject deleteMenu(MpAccount mpAccount)  throws WxErrorException {
        JSONObject rstObj = WxApiClient.deleteMenu(mpAccount);
        if (rstObj != null && rstObj.getIntValue("errcode") == 0) {// 成功，更新菜单组
            menuGroupDao.updateMenuGroupDisable();
        }
        return rstObj;
    }
    public boolean syncAccountFansList(MpAccount mpAccount) throws WxErrorException  {
        String nextOpenId = null;
        AccountFans lastFans = fansDao.getLastOpenId();
        if (lastFans != null) {
            nextOpenId = lastFans.getOpenId();
        }
//        ExecutorService executor = Executors.newSingleThreadExecutor();
//        executor.submit(() -> doSyncAccountFansList(lastFans.getOpenId(), mpAccount));
//        executor.shutdown();
        return doSyncAccountFansList(nextOpenId, mpAccount);
        //return true;
    }
    private boolean doSyncAccountFansList(String nextOpenId, MpAccount mpAccount) throws WxErrorException  {
        String url = WxApi.getFansListUrl(WxApiClient.getAccessToken(mpAccount), nextOpenId);
        logger.info("同步粉丝入参消息如下:" + url);
        JSONObject jsonObject = WxApi.httpsRequest(url, HttpMethod.POST, null);
        logger.info("同步粉丝返回消息如下:" + jsonObject.toString());
        if (jsonObject.containsKey("errcode")) {
            return false;
        }
        List<AccountFans> fansList = new ArrayList<AccountFans>();
        if (jsonObject.containsKey("data")) {
            if (jsonObject.getJSONObject("data").containsKey("openid")) {
                JSONArray openidArr = jsonObject.getJSONObject("data").getJSONArray("openid");
                int length = openidArr.size();
                for (int i = 0; i < length; i++) {
                    Object openId = openidArr.get(i);
                    AccountFans fans = this.syncAccountFans(openId.toString(), mpAccount, true);
                    //AccountFans fans = WxApiClient.syncAccountFans(openId.toString(), mpAccount);
                    fans.setAccount(WxMemoryCacheClient.getAccount());
                    fansList.add(fans);
                }
                fansDao.addList(fansList);
            }
        }
        return true;
    }
    public AccountFans syncAccountFans(String openId, MpAccount mpAccount, boolean merge) throws WxErrorException {
        AccountFans fans = WxApiClient.syncAccountFans(openId, mpAccount);
        if (merge && null != fans) {
            AccountFans tmpFans = fansDao.getByOpenId(openId);
            if (tmpFans == null) {
                fansDao.add(fans);
            } else {
                fans.setId(tmpFans.getId());
                fansDao.update(fans);
            }
        }
        return fans;
    }
    public AccountFans getFansByOpenId(String openId, MpAccount mpAccount) throws WxErrorException {
        AccountFans fans = fansDao.getByOpenId(openId);
        if (fans == null) {// 如果没有，添加
            fans = WxApiClient.syncAccountFans(openId, mpAccount);
            if (null != fans) {
                fansDao.add(fans);
            }
        }
        return fans;
    }
    public boolean syncUserTagList(MpAccount mpAccount) throws WxErrorException {
        String url=null;
        try {
            url = WxApi.getUserTagList(WxApiClient.getAccessToken(mpAccount));
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
        logger.info("同步用户标签参消息如下:"+url);
        JSONObject jsonObject = WxApi.httpsRequest(url, HttpMethod.GET, null);
        logger.info("同步用户标签消息如下:"+jsonObject.toString());
        if(jsonObject.containsKey("errcode")){
            return false;
        }
        JSONArray arr = jsonObject.getJSONArray("tags");//获取jsonArray对象
        String js=JSONObject.toJSONString(arr);//将array数组转换成字符串
        List<UserTag> userTagList=JSONObject.parseArray(js, UserTag.class);//把字符串转换成集合
        Collections.sort(userTagList, new Comparator<UserTag>() {
            @Override
            public int compare(UserTag o1, UserTag o2) {
                return o2.getId().compareTo(o1.getId());
            }
        });
        UserTag userTag = userTagList.get(0);
        Integer maxIdInDb = userTagDao.getMaxId() == null ?  0 : userTagDao.getMaxId();//第一次同步，数据库没有数据返回null
        if (null == userTag.getId() || userTag.getId().intValue() == maxIdInDb.intValue()) {
            return true;
        }else if( userTag.getId() > maxIdInDb ){
            for (UserTag tag: userTagList) {
                if(tag.getId()<=maxIdInDb){
                    userTagList.remove(tag);
                }
            }
            userTagDao.addList(userTagList);
            return true;
        }
        return true;
    }
}
